/*
 * Copyright (c) 2013 WDCY Information Technology Co. Ltd
 * www.wdcy.cc
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * WDCY Information Technology Co. Ltd ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement you
 * entered into with WDCY Information Technology Co. Ltd.
 */
package com.monkey.web.shiro.mgt;

import com.alibaba.fastjson.JSON;
import com.monkey.core.domain.user.User;
import com.monkey.core.domain.user.UserOnlineHistory;
import com.monkey.web.dto.response.user.UserInfoDto;
import com.monkey.web.platform.service.UserOnlineHistoryService;
import com.monkey.web.platform.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * @author Wu Tianqiang
 */
public class MonkeyWebSecurityManager extends DefaultWebSecurityManager {

    @Autowired
    private UserOnlineHistoryService userOnlineHistoryService;
    @Autowired
    private UserService userService;

    private SimpleCookie loggedInCookie;
    private SimpleCookie userCookie;

    @Override
    public void logout(Subject subject) {
        Session session = subject.getSession(false);

        Long userId = (Long) subject.getPrincipal();
        onSuccessfulLogout(userId, session);

        super.logout(subject);
    }

    private void onSuccessfulLogout(Long userId, Session session) {
        if (session == null || userId == null) {
            return;
        }
        UserOnlineHistory userOnlineHistory = createUserLoginHistory(userId, session);
        userOnlineHistoryService.save(userOnlineHistory);
    }

    private UserOnlineHistory createUserLoginHistory(Long userId, Session session) {
        User user = userService.findOne(userId);
        UserOnlineHistory userOnlineHistory = new UserOnlineHistory();
        userOnlineHistory.setUserId(user.getId());
        userOnlineHistory.setAccount(user.getAccount());
        userOnlineHistory.setNick(user.getNick());
        userOnlineHistory.setHost(session.getHost());
//        userOnlineHistory.setUserAgent(session.getUserAgent());
//        userOnlineHistory.setSystemHost(session.getSystemHost());
        userOnlineHistory.setLastLoginTimestamp(session.getStartTimestamp());
        userOnlineHistory.setLastStopTimestamp(new Date());
        userOnlineHistory.incTotalOnlineTime();
        return userOnlineHistory;
    }

    @Override
    protected void beforeLogout(Subject subject) {
        super.beforeLogout(subject);
        forgetIdentity(subject);
    }

    @Override
    protected void onSuccessfulLogin(AuthenticationToken token, AuthenticationInfo info, Subject subject) {
        super.onSuccessfulLogin(token, info, subject);

        HttpServletRequest request = WebUtils.getHttpRequest(subject);
        HttpServletResponse response = WebUtils.getHttpResponse(subject);

        saveLoggedInCookie(token, request, response);
        saveUserCookie(info, token, request, response);

    }

    private void saveUserCookie(AuthenticationInfo info, AuthenticationToken token, HttpServletRequest request, HttpServletResponse response) {
        Long userId = (Long) info.getPrincipals().getPrimaryPrincipal();
        User user = userService.findOne(userId);
        UserInfoDto userInfoDto = new UserInfoDto(user, userService.findPermissions(userId));
        Cookie userCookieTpl = getUserCookie();
        Cookie userCookie = new SimpleCookie(userCookieTpl);
        userCookie.setValue(JSON.toJSONString(userInfoDto));
        if (!isRememberMe(token)) {
            userCookie.setMaxAge(-1);
        }
        userCookie.saveTo(request, response);
    }

    private void saveLoggedInCookie(AuthenticationToken token, HttpServletRequest request, HttpServletResponse response) {
        Cookie loggedInTpl = getLoggedInCookie();
        Cookie loggedInCookie = new SimpleCookie(loggedInTpl);
        loggedInCookie.setValue("true");
        if (!isRememberMe(token)) {
            loggedInCookie.setMaxAge(-1);
        }
        loggedInCookie.saveTo(request, response);
    }

    protected boolean isRememberMe(AuthenticationToken token) {
        return token != null && (token instanceof UsernamePasswordToken) &&
                ((UsernamePasswordToken) token).isRememberMe();
    }

    @Override
    protected void onFailedLogin(AuthenticationToken token, AuthenticationException ae, Subject subject) {
        super.onFailedLogin(token, ae, subject);

        forgetIdentity(subject);
    }

    private void forgetIdentity(Subject subject) {
        HttpServletRequest request = WebUtils.getHttpRequest(subject);
        HttpServletResponse response = WebUtils.getHttpResponse(subject);
        getLoggedInCookie().removeFrom(request, response);
        getUserCookie().removeFrom(request, response);
    }

    public SimpleCookie getLoggedInCookie() {
        return loggedInCookie;
    }

    public void setLoggedInCookie(SimpleCookie loggedInCookie) {
        this.loggedInCookie = loggedInCookie;
    }

    public SimpleCookie getUserCookie() {
        return userCookie;
    }

    public void setUserCookie(SimpleCookie userCookie) {
        this.userCookie = userCookie;
    }
}